/*
    Author: Christopher Diggins
    License: MIT Licence 1.0
    Website: http://www.cdiggins.com
*/

#ifndef LLS_TO_LUA_TABLE_HPP
#define LLS_TO_LUA_TABLE_HPP

namespace lls
{
	struct LLSchemeToLuaTable 
	{
		LuaMachine& L;

		LLSchemeToLuaTable(LuaMachine& lm) 
			: L(lm)
		{ }

		void BeginTable(ConstString s) {
			L += "{\n";
			L += "element = \"";
			L += s;
			L += "\";\n";
		}

		void ChildrenToTable(SExpr* x) {
			L += "{\n";
			x->ForEach(*this);
			L += "};\n";
		}

		void EndTable() {
			L += "};\n";
		}

		void AddField(ConstString name) {
			L += name;
			L += " = ";
		}

		void AddField(ConstString name, ConstString val) {
			AddField(name);
			L += "\"";
			L += val;
			L += "\"";
			L += ";\n";
		}

		void AddField(ConstString name, SExpr* x) {
			AddField(name);
			(*this)(x);
		}

		void AddValue(ConstString s) {
			L += "\"";
			L += EscapeStr(s);
			L += "\";\n";
		}

		void operator()(SExpr* x) {
			if (x->Is<Module>()) { 
				Module* t = x->As<Module>();
				BeginTable("module");
				AddField("name", t->GetNameStr());
				AddField("classes");
				ChildrenToTable(t);
				EndTable();
			}
			else if (x->Is<Class>()) {
				Error("unimplemented");
			}
			else if (x->Is<Define>()) {
				Define* t = x->As<Define>();
				BeginTable("func");
				AddField("name", t->GetNameStr());
				AddField("formals", t->GetFormals());
				AddField("type", t->GetType()->Label());
				AddField("body", t->Body());
				EndTable();
			}
			else if (x->Is<SetField>()) {
				SetField* t = x->As<SetField>();
				BeginTable("setfield");
				AddField("object", t->Object());
				AddField("name", t->GetNameStr());
				AddField("value", t->GetVal());
				EndTable();
			}
			else if (x->Is<GetField>()) {
				GetField* t = x->As<GetField>();
				BeginTable("getfield");
				AddField("object", t->Object());
				AddField("name", t->GetNameStr());
				EndTable();
			}
			else if (x->Is<New>()) {
				New* t = x->As<New>();
				BeginTable("new");
				AddField("args", t->GetArgs());
				EndTable();
			}
			else if (x->Is<Args>()) {
				Args* t = x->As<Args>();
				ChildrenToTable(t);
			}
			else if (x->Is<Set>()) { 
				Set* t = x->As<Set>();
				BeginTable("set");
				AddField("name", t->GetNameStr());
				AddField("value", t->GetVal());
				EndTable();
			}
			else if (x->Is<Get>()) { 
				Get* t = x->As<Get>();
				BeginTable("get");
				AddField("name", t->GetNameStr());
				EndTable();
			}
			else if (x->Is<SetAt>()) { 
				SetAt* t = x->As<SetAt>();
				BeginTable("setat");
				AddField("object", t->Collection());
				AddField("index", t->Index());
				AddField("value", t->GetVal());
				EndTable();
			}
			else if (x->Is<GetAt>()) { 
				GetAt* t = x->As<GetAt>();
				BeginTable("getat");
				AddField("object", t->Collection());
				AddField("index", t->Index());
				EndTable();
			}
			else if (x->Is<Literal>()) { 
				if (x->Is<PLiteral<int> >()) {
					PLiteral<int>* t = x->As<PLiteral<int> >();				
					BeginTable("literal_int");
					AddField("value", t->data);
					EndTable();
				}
				else if (x->Is<PLiteral<String> >()) {
					PLiteral<String>* t = x->As<PLiteral<String> >();
					BeginTable("literal_string");
					AddField("value", t->data);
					EndTable();
				}
				else {
					Error("unhandled literal " + x->As<Literal>()->data);
				}
			}
			else if (x->Is<Name>()) { 
				Name* t = x->As<Name>();
				BeginTable("name");
				AddField("value", t->data);
				EndTable();
			}
			else if (x->Is<Var>()) { 
				Var* t = x->As<Var>();
				BeginTable("vardecl");
				AddField("name", t->GetNameStr());
				if (t->GetVal() != NULL) {
					AddField("value", t->GetVal());
				}
				EndTable();
			}
			else if (x->Is<Return>()) { 
				Return* t = x->As<Return>();
				BeginTable("return");
				if (t->GetVal() != NULL) {
					AddField("value", t->GetVal());
				}
				EndTable();
			}
			else if (x->Is<If>()) { 
				If* t = x->As<If>();
				BeginTable("if");
				AddField("condition",t->Cond());
				AddField("ontrue", t->TrueBranch());
				if (t->FalseBranch() != NULL)
					AddField("onfalse", t->FalseBranch());
				EndTable();
			}
			else if (x->Is<Invoke>()) { 
				Invoke* t = x->As<Invoke>();
				BeginTable("invoke");
				AddField("object", t->Object());
				AddField("name", t->GetNameStr());
				AddField("args", t->GetArgs());
				EndTable();
			}
			else if (x->Is<Apply>()) { 
				Apply* t = x->As<Apply>();
				BeginTable("call");
				AddField("func", t->Func());
				AddField("args", t->GetArgs());
				EndTable();
			}
			else if (x->Is<While>()) { 
				While* t = x->As<While>();
				BeginTable("while");
				AddField("condition", t->Cond());
				AddField("body", t->Body());
				EndTable();
			}
			else if (x->Is<Seq>()) {
				Seq* t = x->As<Seq>();
				BeginTable("block");
				AddField("statements");
				ChildrenToTable(t);
				EndTable();
			}
			else if (x->Is<ForEachIndex>()) { 
				ForEachIndex* t = x->As<ForEachIndex>();
				Error("unimplemented");
			}
			else if (x->Is<ForEach>()) { 
				ForEach* t = x->As<ForEach>();
				BeginTable("foreach");
				AddField("index", t->GetNameStr());
				AddField("type", t->GetType()->Label());
				AddField("object", t->List());
				AddField("body", t->Body());
				EndTable();
			}
			else if (x->Is<For>()) { 
				For* t = x->As<For>();
				BeginTable("foreach");
				AddField("index", t->GetNameStr());
				AddField("init", t->Init());
				AddField("inv", t->Inv());
				AddField("next", t->Next());
				AddField("body", t->Body());
				EndTable();
			}
			else if (x->Is<Formal>()) { 
				Formal* t = x->As<Formal>();
				BeginTable("formal");
				AddField("name", t->GetNameStr());
				AddField("type", t->GetTypeStr());
				EndTable();
			}
			else if (x->Is<Formals>()) { 
				Formals* t = x->As<Formals>();
				ChildrenToTable(t);
			}
			else if (x->Is<Lambda>()) { 
				Lambda* t = x->As<Lambda>();
				Error("unimplemented");
			}
			else if (x->Is<TransformAt>()) { 
				Error("unimplemented");
			}
			else if (x->Is<Primitive>()) { 
				Primitive* t = x->As<Primitive>();
				BeginTable(t->IdStr());
				AddField("args");
				ChildrenToTable(t);
				EndTable();
			}
			else if (x->Is<Import>()) { 
				Error("unimplemented");
			}
			else {
				Error("unhandled s-expression: " + x->ToString());
			}
		}
	};
}

#endif
